package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"google.golang.org/protobuf/proto"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/gorilla/websocket"
	"main/douyin"
)

type WebSocketApp struct {
	LiveID     string
	LiveURL    string
	UserAgent  string
	ttwid      string
	roomID     string
	Conn       *websocket.Conn
	httpClient *http.Client
}

func NewSpiderApp(liveID string) WebSocketApp {
	// 创建 WebSocketApp 实例并生成 ttwid
	wsApp := WebSocketApp{
		LiveID:    liveID,                                                                                                            // 替换为实际的 room_id
		LiveURL:   "https://live.douyin.com/",                                                                                        // 替换为实际的直播间 URL
		UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", // 替换为实际的 User-Agent
	}

	// 获取并打印 ttwid
	wsApp.GetTTWID()
	wsApp.GetRoomID()

	return wsApp
}

// connectWebSocket 连接抖音直播间 WebSocket
func (w *WebSocketApp) connectWebSocket() {
	wss := fmt.Sprintf("wss://webcast5-ws-web-hl.douyin.com/webcast/im/push/v2/?app_name=douyin_web"+
		"&version_code=180800&webcast_sdk_version=1.0.14-beta.0&update_version_code=1.0.14-beta.0"+
		"&compress=gzip&device_platform=web&cookie_enabled=true&screen_width=1536&screen_height=864"+
		"&browser_language=zh-CN&browser_platform=Win32&browser_name=Mozilla&browser_version=5.0%%20(Windows%%20NT%%2010.0;"+
		"%%20Win64;%%20x64)%%20AppleWebKit/537.36%%20(KHTML,%%20like%%20Gecko)%%20Chrome/126.0.0.0%%20Safari/537.36"+
		"&browser_online=true&tz_name=Asia/Shanghai&cursor=d-1_u-1_fh-7392091211001140287_t-1721106114633_r-1"+
		"&internal_ext=internal_src:dim|wss_push_room_id:%s|wss_push_did:7290648722612946472|first_req_ms:1721106114541"+
		"|fetch_time:1721106114633|seq:1|wss_info:0-1721106114633-0-0|wrds_v:7392094459690748497"+
		"&host=https://live.douyin.com&aid=6383&live_id=1&did_rule=3&endpoint=live_pc&support_wrds=1"+
		"&user_unique_id=7290648722612946472&im_path=/webcast/im/fetch/&identity=audience"+
		"&need_persist_msg_count=15&insert_task_id=&live_reason=&room_id=%s&heartbeatDuration=0",
		w.roomID, w.roomID)

	// 生成签名
	signature, err := w.generateSignature(wss)
	if err != nil {
		log.Fatalf("生成签名失败: %v", err)
	}
	signature = strings.Replace(signature, "\n", "", 1)

	// 添加签名到 WebSocket URL
	wss += fmt.Sprintf("&signature=%s", signature)
	// 设置请求头
	headers := http.Header{}
	headers.Set("cookie", fmt.Sprintf("ttwid=%s", w.ttwid))
	headers.Set("user-agent", w.UserAgent)

	// 连接到 WebSocket
	conn, _, err := websocket.DefaultDialer.Dial(wss, headers)
	if err != nil {
		log.Fatalf("连接 WebSocket 失败: %v", err)
	}
	w.Conn = conn
	defer conn.Close()

	// 开始监听消息
	for {
		_, message, err := conn.ReadMessage()
		if err != nil {
			log.Fatalf("读取 WebSocket 消息失败: %v", err)
		}

		// 这里可以添加对消息的处理逻辑
		w.handleMessage(message)
	}
}

// handleMessage 处理收到的 WebSocket 消息
func (w *WebSocketApp) handleMessage(message []byte) {
	// 解析 WebSocket 消息为 PushFrame（假设 PushFrame 是 protobuf 生成的结构体）
	packageFrame := &douyin.PushFrame{} // 替换为实际的 protobuf 包路径
	err := proto.Unmarshal(message, packageFrame)
	if err != nil {
		log.Printf("Failed to parse PushFrame: %v", err)
		return
	}

	// 将 payload 转换为 io.Reader
	payloadReader := bytes.NewReader(packageFrame.GetPayload())

	// 使用 GZIP 解压 payload
	gzipReader, err := gzip.NewReader(payloadReader)
	if err != nil {
		log.Printf("Failed to create gzip reader: %v", err)
		return
	}
	defer gzipReader.Close()

	// 读取解压后的数据
	decompressedPayload, err := ioutil.ReadAll(gzipReader)
	if err != nil {
		log.Printf("Failed to read decompressed payload: %v", err)
		return
	}

	// 将解压后的数据解析为 Response 结构体
	response := &douyin.Response{}
	err = proto.Unmarshal(decompressedPayload, response)
	if err != nil {
		log.Printf("Failed to parse Response: %v", err)
		return
	}

	// 如果需要 ACK，发送确认消息
	if response.GetNeedAck() {
		ack := &douyin.PushFrame{
			LogId:       packageFrame.GetLogId(),
			PayloadType: "ack", // 替换为实际的枚举值
			Payload:     []byte(response.GetInternalExt()),
		}
		ackData, err := proto.Marshal(ack)
		if err != nil {
			log.Printf("Failed to serialize ACK message: %v", err)
			return
		}

		err = w.Conn.WriteMessage(websocket.BinaryMessage, ackData)
		if err != nil {
			log.Printf("Failed to send ACK message: %v", err)
			return
		}
	}

	// 遍历并处理不同类型的消息
	for _, msg := range response.MessagesList {
		switch msg.Method {
		case "WebcastChatMessage": // 聊天消息
			w.parseChatMsg(msg.GetPayload())
		case "WebcastGiftMessage": // 礼物消息
			w.parseGiftMsg(msg.GetPayload())
		case "WebcastLikeMessage": // 点赞消息
			w.parseLikeMsg(msg.GetPayload())
		case "WebcastMemberMessage": // 进入直播间消息
			w.parseMemberMsg(msg.GetPayload())
		case "WebcastSocialMessage": // 关注消息
			w.parseSocialMsg(msg.GetPayload())
		case "WebcastRoomUserSeqMessage": // 直播间统计
			w.parseRoomUserSeqMsg(msg.GetPayload())
		case "WebcastRoomStatsMessage": // 直播间统计信息
			w.parseRoomStatsMsg(msg.GetPayload())
		case "WebcastRoomRankMessage": // 直播间排行榜信息
			w.parseRoomRankMsg(msg.GetPayload())
		case "WebcastControlMessage": // 直播间状态消息
			w.parseControlMsg(msg.GetPayload())
		default:

		}
	}
}

func main() {
	// 创建 WebSocketApp 实例并生成 ttwid
	var liveID string
	if len(os.Args) < 2 {
		fmt.Print("请输入直播间号: ")
		fmt.Scanln(&liveID) // 读取用户输入，直到遇到回车
	} else {
		liveID = os.Args[1]
	}

	spiderApp := NewSpiderApp(liveID)
	spiderApp.connectWebSocket()
}
